using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using ERP.Model;

namespace ERP.IDAL
{
    /// <summary>
    /// 仓储接口定义
    /// </summary>
    public interface IRepositoryBase
    {
    }
    /// <summary>
    /// 定义泛型仓储接口
    /// </summary>
    /// <typeparam name="TEntity">实体</typeparam>
    /// <typeparam name="TPrimaryKey">主键类型</typeparam>
    public interface IRepositoryBase<TEntity, TPrimaryKey> : IRepositoryBase where TEntity : BaseEntity<TPrimaryKey>
    {
        #region 查询集合
        /// <summary>
        /// 获取表整体检索
        /// </summary>
        /// <returns></returns>
        IQueryable<TEntity> GetAll();

        /// <summary>
        /// 获取表整体检索(多表关联)
        /// </summary>
        /// <param name="propertySelectors">参数条件</param>
        /// <returns></returns>
        IQueryable<TEntity> GetAllIncluding(params Expression<Func<TEntity, object>>[] propertySelectors);

        /// <summary>
        /// 获取实体集合
        /// </summary>
        /// <returns></returns>
        Task<List<TEntity>> GetAllListAsync();

        /// <summary>
        /// 根据Lambda表达式获取实体集合
        /// </summary>
        /// <param name="predicate">Lambda表达式条件</param>
        /// <returns></returns>
        Task<List<TEntity>> GetAllListAsync(Expression<Func<TEntity, bool>> predicate);
        #endregion

        #region 查询实体
        /// <summary>
        /// 根据主键获取实体
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        TEntity Get(TPrimaryKey id);

        /// <summary>
        /// 根据主键获取实体
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        Task<TEntity> GetAsync(TPrimaryKey id);

        /// <summary>
        /// 根据主键获取实体,如果没有查到则返回空
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        TEntity FirstOrDefault(TPrimaryKey id);

        /// <summary>
        /// 根据Lambda表达式条件获取实体,如果没有查到则返回空
        /// </summary>
        /// <param name="predicate">Lambda表达式条件</param>
        /// <returns></returns>
        TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate);

        /// <summary>
        /// 根据主键获取实体,如果没有查到则返回空
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        Task<TEntity> FirstOrDefaultAsync(TPrimaryKey id);

        /// <summary>
        /// 根据Lambda表达式条件获取实体,如果没有查到则返回空
        /// </summary>
        /// <param name="predicate">Lambda表达式条件</param>
        /// <returns></returns>
        Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate);
        #endregion

        #region 插入实体
        /// <summary>
        /// 插入实体
        /// </summary>
        /// <param name="entity">实体</param>
        /// <returns></returns>
        TEntity Insert(TEntity entity);

        /// <summary>
        /// 插入实体
        /// </summary>
        /// <param name="entity">实体</param>
        /// <returns></returns>
        Task<TEntity> InsertAsync(TEntity entity);

        /// <summary>
        /// 插入实体并获取主键
        /// </summary>
        /// <param name="entity">实体</param>
        /// <returns></returns>
        TPrimaryKey InsertAndGetId(TEntity entity);

        /// <summary>
        /// 插入实体并获取主键
        /// </summary>
        /// <param name="entity">实体</param>
        /// <returns></returns>
        Task<TPrimaryKey> InsertAndGetIdAsync(TEntity entity);
        #endregion

        #region 更新实体
        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="updateAction">被更改的属性</param>
        /// <returns></returns>
        TEntity Update(TEntity entity, Action<TEntity> updateAction = null);

        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="updateAction">被更改的属性</param>
        /// <returns></returns>
        Task<TEntity> UpdateAsync(TEntity entity, Action<TEntity> updateAction = null);

        #endregion

        #region 插入或更新实体
        /// <summary>
        /// 插入或更新实体
        /// </summary>
        /// <param name="entity">实体</param>
        /// <returns></returns>
        TEntity InsertOrUpdate(TEntity entity);
        /// <summary>
        /// 插入或更新实体
        /// </summary>
        /// <param name="entity">实体</param>
        /// <returns></returns>
        Task<TEntity> InsertOrUpdateAsync(TEntity entity);
        #endregion

        #region 删除实体
        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="entity">实体</param>
        void Delete(TEntity entity);

        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="entity">实体</param>
        Task DeleteAsync(TEntity entity);

        /// <summary>
        /// 根据Id删除实体
        /// </summary>
        /// <param name="id">主键</param>
        void Delete(TPrimaryKey id);

        /// <summary>
        /// 根据Id删除实体
        /// </summary>
        /// <param name="id">主键</param>
        Task DeleteAsync(TPrimaryKey id);

        /// <summary>
        /// 根据条件删除实体
        /// </summary>
        /// <param name="predicate">Lambda表达式</param>
        void Delete(Expression<Func<TEntity, bool>> predicate);

        /// <summary>
        /// 根据条件删除实体
        /// </summary>
        /// <param name="predicate">Lambda表达式</param>
        Task DeleteAsync(Expression<Func<TEntity, bool>> predicate);
        #endregion

        #region 分页查询
        /// <summary>
        /// 分页获取数据
        /// </summary>
        /// <param name="startPage">起始页</param>
        /// <param name="pageSize">单页行数</param>
        /// <param name="rowCount">总行数</param>
        /// <param name="predicate">查询条件</param>
        /// <param name="order">排序</param>
        /// <param name="isAcs">是否是升序</param>
        /// <returns></returns>
        IQueryable<TEntity> LoadPageList<TSKey>(int startPage, int pageSize, out int rowCount,
            Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TSKey>> order, bool isAcs);

        #endregion

        #region 统一提交数据
        /// <summary>
        /// 统一提交数据
        /// </summary>
        void Save();
        #endregion
    }

    /// <summary>
    /// 默认long主键类型仓储
    /// </summary>
    /// <typeparam name="TEntity">实体</typeparam>
    public interface IRepositoryBase<TEntity> : IRepositoryBase<TEntity, Guid> where TEntity : BaseEntity
    {

    }
}